package com.kasa.gps.service;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.sql.Time;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TreeMap;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

import com.kasa.gps.OrderGPSActivity;
import com.kasa.gps.OrderGPSMapActivity;
import com.kasa.gps.R;
import com.kasa.gps.alarm.OrderGPSReceiver;
import com.kasa.gps.db.table.LocationInfoTableAdapter;
import com.kasa.gps.db.table.VehiclesInfoTableAdapter;
import com.kasa.gps.tool.Tool;
import com.kasa.zto.NumberUtils;
import com.kasa.zto.SOSEncoder;
import com.kasa.zto.common.CommConstant;
import com.kasa.zto.common.CommHead;
import com.kasa.zto.common.LancomeData;
import com.kasa.zto.common.LjgjRequest;
import com.kasa.zto.common.Tools;

/**
 * 跟踪服务
 * */
public class TrackService extends Service {
	
	private static final DateFormat UPDATE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	private static LocationManager locationManager = null;
	private static LocationListener locationListener = null;
	private static Location currentLocation = null;
	private Geocoder geocoder = null;
	private List<Address> addressList = null;
	private static VehiclesInfoTableAdapter vehiclesInfoTable = null;
	private static LocationInfoTableAdapter locationInfoTable = null;
	private static Tool tool = null;
	
	private static OrderGPSActivity.LocationHandler handler = null;
	private static OrderGPSMapActivity.UpdateLocationHandler updateLocationHandler = null;
	
	private static int vehiclesinfoId = 0;
	private static String licensePlates = "";
	private static String transportPlans = "";
	private static String alarmTime = "";
	
	private static String area = "";
	private static String stree = "";
	private static String updatetime = "";
	
	private static long locationUpdateFrequency = 60000;
	private static long dataUploadFrequency = 60000;
	private static long locationUpdateDistance = 1000;
	
	
	private NotificationManager notificationManager = null;
	private Notification notification = null;
	
	private static AlarmManager alarmManager = null;
	private static PendingIntent operation = null;
	
	private static DataUploadThread dataUploadThread = null;
	
	private static double OFF_LONGITUDE = 0.004D;
	private static double OFF_LATITUDE = 0.003D;
	
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	/***不管调用startService(intent)多少次，在stopService(intent)调用之前，onCreate()都是运行一次*/
	@Override
	public void onCreate() {
		//
		tool = new Tool(this);
		//
		handler = new OrderGPSActivity.LocationHandler();
		updateLocationHandler = new OrderGPSMapActivity.UpdateLocationHandler();
		//
		vehiclesInfoTable = new VehiclesInfoTableAdapter(this);
		locationInfoTable = new LocationInfoTableAdapter(this);
		//
		locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
		locationListener = new OrderLocationListener();
		//
		geocoder = new Geocoder(getBaseContext(),Locale.CHINESE);
		
		//
		alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
		operation = PendingIntent.getBroadcast(this, 0, new Intent(this,OrderGPSReceiver.class), 0);
		//
		notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
		notification = new Notification();
		Log.i("TrackService", "onCreate...");
	}
	/**和startService(intent)调用次数一样*/
	@Override
	public void onStart(Intent intent, int startId) {
		
		//车辆信息id
		vehiclesinfoId = intent.getIntExtra(VehiclesInfoTableAdapter.ID, 0);
		//车牌号码
		licensePlates = intent.getStringExtra(VehiclesInfoTableAdapter.LICENSE_PLATES);
		//运输计划
		transportPlans = intent.getStringExtra(VehiclesInfoTableAdapter.TRANSPORT_PLANS);
		//计划完成时间
		alarmTime = intent.getStringExtra(VehiclesInfoTableAdapter.EXPECTED_TIME);
		//位置更新频率
		locationUpdateFrequency = tool.getFrequency(vehiclesInfoTable.getLocationUpdateFrequency(vehiclesinfoId),tool.UNITS_TIME);
		//位置更新间距
		locationUpdateDistance = tool.getFrequency(vehiclesInfoTable.getLocationUpdateDistance(vehiclesinfoId),tool.UNITS_DISTANCE);
		//数据上传频率
		dataUploadFrequency = tool.getFrequency(vehiclesInfoTable.getDataUploadFrequency(vehiclesinfoId),tool.UNITS_TIME);
		
		//自定义标准
		Criteria mCriteria = new Criteria();
		mCriteria.setAccuracy(Criteria.ACCURACY_FINE);// 精度
		mCriteria.setAltitudeRequired(false);// 海拔
		mCriteria.setBearingRequired(false);// 方向,气压
		mCriteria.setSpeedRequired(true);
		mCriteria.setCostAllowed(true);// 费用
		mCriteria.setPowerRequirement(Criteria.POWER_LOW);// 电量
		//位置供应商
		String bestLocationPrivider = locationManager.getBestProvider(mCriteria,true);
		//初始化当前位置，使用上一个已知的位置来得到一个快速的位置修正
		
		try {
			currentLocation = locationManager.getLastKnownLocation(bestLocationPrivider);//bestLocationPrivider
		} catch (IllegalArgumentException e) {
			Log.i("getLastKnownLocation", e.toString());
		}
		//注销监听器，长时间的监听位置更新会消耗大量电量。一旦得到你所需要的信息之后，你应当立即调用removeUpdates(PendingIntent)方法停止监听
		locationManager.removeUpdates(locationListener);
		//注册监听器
		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, locationUpdateFrequency, locationUpdateDistance, locationListener);
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, locationUpdateFrequency, locationUpdateDistance, locationListener);
		//状态栏显示图标////////////////////////////////////////////////////////////
		//转跳目标
		Intent target = new Intent(TrackService.this,OrderGPSActivity.class);
		//target.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		//
		//target.putExtra(VehiclesInfoTableAdapter.LICENSE_PLATES, licensePlates);
		//target.putExtra(VehiclesInfoTableAdapter.TRANSPORT_PLANS, transportPlans);
		PendingIntent contentIntent = PendingIntent.getActivity(TrackService.this, 0, target, 0);
		//
		String title = getString(R.string.app_name);
		//在状态栏显示的图标
		notification.icon = R.drawable.icon;
		//显示文本
		notification.tickerText = title;
		//标记：在“正在运行”组注册，不清除图标
		notification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
		notification.setLatestEventInfo(TrackService.this, title, getString(R.string.notification_show_msg), contentIntent);
		//发出通知
		notificationManager.notify(R.string.app_name, notification);
		
		//计划即将完成提醒////////////////////////////////////////
		Calendar triggerAtTime = Calendar.getInstance();
		try {
			//设置触发时间点
			triggerAtTime.setTime(Tool.ALARM_DATE_FORMAT.parse(alarmTime));
			//注册闹铃
			alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtTime.getTimeInMillis(), operation);
			
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
		//如果处理过程太耗时，为避免服务太久不响应而导致系统报错，故由启动线程处理
		new onStartThread().start();
		
	}
	
	@Override
	public void onDestroy() {
		//注销监听器
		locationManager.removeUpdates(locationListener);
		locationListener = null;
		locationManager = null;
		
		vehiclesInfoTable = null;
		locationInfoTable = null;
		handler = null;
		addressList = null;
		geocoder = null;
		
		//取消通知
		notificationManager.cancel(R.string.app_name);
		notificationManager = null;
		notification = null;
		
		//注销闹铃
		alarmManager.cancel(operation);
		alarmManager = null;
		operation = null;
		
		
		Log.i("TrackService", "onDestroy...");
	}
	
	/**耗时的过程，尽量放入线程运行*/
	private class onStartThread extends Thread{
		
		public void run(){
			
			//更新UI界面
			updateUI(currentLocation);
			//启动数据上传线程
			String[] uploadServer = vehiclesInfoTable.getUploadServer(vehiclesinfoId).split(Tool.SPLIT_ADDR_PORT);
			if(dataUploadThread == null || !dataUploadThread.isAlive()){
				dataUploadThread = new DataUploadThread(currentLocation,new InetSocketAddress(uploadServer[0], Integer.parseInt(uploadServer[1])));
				dataUploadThread.start();
			}
			vehiclesInfoTable.close();
			Log.i("TrackService", "onStart..."+currentLocation);
			
		}
	}
	

	private void updateUI(Location location) {
		
		Log.i("updateUI", "updateUI..." + location);
		if (location != null) {
			
			location.setLatitude(location.getLatitude() - OFF_LATITUDE);
			location.setLongitude(location.getLongitude() + OFF_LONGITUDE);
			try {
				addressList = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
			} catch (IOException e) {
				e.printStackTrace();
			}

			//如果可以找到地址
			if (addressList != null && addressList.size() > 0) {
				for (Address address : addressList) {
					//Log.i("geocoder.getFromLocation", address.toString());
					area = address.getAddressLine(0)+address.getAddressLine(1);
					stree = address.getAddressLine(2);
					updatetime = UPDATE_DATE_FORMAT.format(new Date());
				}
			}else{
				area = "";
				stree = "";
				updatetime = UPDATE_DATE_FORMAT.format(new Date());
			}
			
			// 将要更新的data传入，方便界面接收显示
			Bundle data = new Bundle();
			data.putString(LocationInfoTableAdapter.LONGITUDE, location.getLongitude() + "");
			data.putString(LocationInfoTableAdapter.LATITUDE, location.getLatitude() + "");
			data.putString(LocationInfoTableAdapter.AREA, area);
			data.putString(LocationInfoTableAdapter.STREE, stree);
			data.putString(LocationInfoTableAdapter.UPDATETIME, updatetime);
			data.putString(LocationInfoTableAdapter.SPEED, (location.getSpeed()*3.6)+"公里/时");
			Message msg = handler.obtainMessage(handler.WHAT_UPDATE_MAINUI_0);
			msg.setData(data);
			// 更新主界面相关信息
			handler.sendMessage(msg);
			
			//更新地图位置
			Bundle datalocation = new Bundle();
			Message updatemap = updateLocationHandler.obtainMessage(updateLocationHandler.WHAT_UPDATE_LOCATION_0);		
			datalocation.putParcelable(updateLocationHandler.LOCATION_KEY, location);
			updatemap.setData(datalocation);
			updateLocationHandler.sendMessage(updatemap);
		}
	}

	class OrderLocationListener implements LocationListener{

		@Override
		public void onLocationChanged(Location location) {
			Log.i("onLocationChanged", location+"");
			currentLocation = location;
			updateUI(location);
			
		}

		@Override
		public void onProviderDisabled(String provider) {
			handler.sendEmptyMessage(handler.WHAT_PROVIDER_DISABLED_3);
			Log.i("onProviderDisabled", "provider="+provider);
		}

		@Override
		public void onProviderEnabled(String provider) {
			handler.sendEmptyMessage(handler.WHAT_PROVIDER_ENABLED_4);
			Log.i("onProviderEnabled", "provider="+provider);
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			//Bundle data = new Bundle();
			Log.i("onStatusChanged", "provider="+provider + ",status="+status+",extras="+extras.toString());
			Bundle data = new Bundle();
			data.putInt("StatusChanged", status);
			Message msg = handler.obtainMessage(handler.WHAT_PROVIDER_STATUS_CHANGED_5);
			msg.setData(data);
			handler.sendMessage(msg);
		}
		
	}
		
	private static TreeMap<Long,OrderLocation> locationMap = null;
	class DataUploadThread extends Thread{
		
		private InetSocketAddress uploadServer ;
		
		private Location lastLocation = null;
			
		public DataUploadThread(Location location,InetSocketAddress uploadServer){
			this.uploadServer = uploadServer;
			locationMap = new TreeMap<Long,OrderLocation>();
			if(location!=null){
				lastLocation = location;
			}
		}
		
		public void run(){
			while(Tool.isServiceRunning(TrackService.this, TrackService.class.getName())){
				Log.i("DataUploadThread", "try to upload data ...");
				sendData(false,"");
				
				try {
					sleep(dataUploadFrequency);
				} catch (InterruptedException e) {
					Log.i("DataUploadThread", e.toString());
				}
			}
		}

		public InetSocketAddress getUploadServer() {
			return uploadServer;
		}

		public void setUploadServer(InetSocketAddress uploadServer) {
			this.uploadServer = uploadServer;
		}

		public Location getLastLocation() {
			return lastLocation;
		}

		public void setLastLocation(Location lastLocation) {
			this.lastLocation = lastLocation;
		}
		
		

		
	}
	
	private static byte[] genData(TreeMap<Long,OrderLocation> orderLocationMap){

        CommHead head = new CommHead();
        head.cmdCode = 3055;
        head.moduleName = "storagemodule";
        head.userName = "admin";
        head.messageType = CommConstant.MESSAGE_TYPE_ASYN;
        
        LjgjRequest request = new LjgjRequest();
        
        for(OrderLocation orderLocation:orderLocationMap.values()){
        	request.list.add(orderLocation.toPczbljgjRequest());
        }
		
        LancomeData data = new LancomeData();
        data.head = head;
        data.data = request;
        
		try {
			SOSEncoder encoder = new SOSEncoder();
			data.encode(encoder);
			byte[] content = encoder.getBytesData();
			content = Tools.gZip(content);

			int length = content.length;
			byte[] size = NumberUtils.int2byte(length);

			ByteBuffer buffer = ByteBuffer.allocate(4 + length);
			buffer.put(size);
			buffer.put(content);
			Log.i("genData", buffer.toString());
			// 然后发送buffer里的字节数组就好
			return buffer.array();
		} catch (Exception e) {
			e.printStackTrace();
		}
    
        return null;
	}
	
	/**判断前后两个位置，哪个更好*/
	private static boolean isBetterLocation(Location lastLocation,Location nowLocation) {
		if(null == nowLocation)
		{
			return false;
		}
		
		if (lastLocation == null) {
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = nowLocation.getTime() - lastLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > locationUpdateFrequency;
		boolean isSignificantlyOlder = timeDelta < -locationUpdateFrequency;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use  the new location because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be  worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (nowLocation.getAccuracy() - lastLocation .getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(nowLocation.getProvider(), lastLocation.getProvider());

		// Determine location quality using a combination of timeliness and accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return true;
		}
		return false;
	}

	/**比对位置供应商是否相同 */
	private static boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}
	
	private static void sendData(boolean closeService,String remarks){
		//如果位置相差不大，可以不上传
		if(isBetterLocation(dataUploadThread.getLastLocation(),currentLocation)){
			Log.i("DataUploadThread", "upload data ..."+currentLocation.toString());
			
			//入库
			locationInfoTable.insertLocationInfo(vehiclesinfoId, currentLocation.getLongitude(), currentLocation.getLatitude(), area, stree, updatetime);
			
			OrderLocation orderLocation = new OrderLocation();
			orderLocation.setLicensePlates(licensePlates);
			orderLocation.setTransportPlans(transportPlans);
			orderLocation.setDate(new Date());
			orderLocation.setTime(new Time(System.currentTimeMillis()));
			orderLocation.setLongitude(currentLocation.getLongitude()+"");
			orderLocation.setLatitude(currentLocation.getLatitude()+"");
			orderLocation.setAdrress(area + stree);
			orderLocation.setSpeed((double)currentLocation.getSpeed()*3.6);
			orderLocation.setRemarks(remarks);

			locationMap.put(System.currentTimeMillis(), orderLocation);
			byte[] senddata = genData(locationMap);
			//历史队列有数据，则先处理队列的数据
			
			int tryTimes = 3;
			for(int i=0;i<tryTimes;i++){
				Socket socket = new Socket();
				try {
					socket.connect(dataUploadThread.getUploadServer(), 3000);
					OutputStream out= socket.getOutputStream();
					out.write(senddata);
					out.flush();
					out.close();
					socket.close();
					dataUploadThread.setLastLocation(currentLocation);
					locationMap.clear();
					//上传成功，则设置手工上传按钮为不可用。
					Bundle data = new Bundle();
					data.putBoolean(Tool.CLOSE_SERVICE_KEY, closeService);
					Message msg = handler.obtainMessage(handler.WHAT_UPLOAD_SUCCESS_1);
					msg.setData(data);
					handler.sendMessage(msg);
					
					Log.i("DataUploadThread", "sentData ...");
					//退出循环
					break;
				
				} catch (Exception e1) {
					e1.printStackTrace();
					
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} 
			}
			
		
		}
	}
	
	public static class TrackServiceHandler extends Handler{
		public final byte WHAT_UPLOAD_0 = 0;
		public final byte WHAT_DELAYSERVICE_1 = 1;
		
		public final byte WHAT_EXPECTED_TIME_CHANGE_2 = 2;
		public final byte WHAT_LOCATON_UPDATE_CHANGE_3 = 3;
		public final byte WHAT_DATA_UPLOAD_CHANGE_4 = 4;
		
		@Override
		public void handleMessage(Message msg) {
			//如果该数据还没有上传，则执行上传动作
			if(msg.what == WHAT_UPLOAD_0){
				Bundle data = msg.getData();
				sendData(data.getBoolean(Tool.CLOSE_SERVICE_KEY),data.getString(Tool.REMARKS_TEXT_KEY));
			}else if(msg.what == WHAT_DELAYSERVICE_1){
				alarmTime = msg.getData().getString(VehiclesInfoTableAdapter.EXPECTED_TIME);
				//修改数据库数据
				vehiclesInfoTable.updateExpectedTime(vehiclesinfoId, alarmTime);
				vehiclesInfoTable.close();
				
				//重新注册
				alarmManager.cancel(operation);
				Calendar triggerAtTime = Calendar.getInstance();
				try {
					//设置触发时间点
					triggerAtTime.setTime(Tool.ALARM_DATE_FORMAT.parse(alarmTime));
					//注册闹铃
					alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtTime.getTimeInMillis(), operation);
					handler.sendEmptyMessage(handler.WHAT_TO_MAINUI_2);
				} catch (ParseException e) {
					e.printStackTrace();
				}
			}
			
			//如果后台服务已经启动
			if(tool != null){
				if(msg.what == WHAT_EXPECTED_TIME_CHANGE_2){
					//
					alarmTime = vehiclesInfoTable.getExpectedTime(vehiclesinfoId);
					//重新注册
					alarmManager.cancel(operation);
					Calendar triggerAtTime = Calendar.getInstance();
					try {
						//设置触发时间点
						triggerAtTime.setTime(Tool.ALARM_DATE_FORMAT.parse(alarmTime));
						//注册闹铃
						alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtTime.getTimeInMillis(), operation);
					} catch (ParseException e) {
						e.printStackTrace();
					}
					
				}
				if(msg.what == WHAT_LOCATON_UPDATE_CHANGE_3){
					//
					//位置更新频率
					locationUpdateFrequency = tool.getFrequency(vehiclesInfoTable.getLocationUpdateFrequency(vehiclesinfoId),tool.UNITS_TIME);
					//位置更新间距
					locationUpdateDistance = tool.getFrequency(vehiclesInfoTable.getLocationUpdateDistance(vehiclesinfoId),tool.UNITS_DISTANCE);
					//注销监听器，长时间的监听位置更新会消耗大量电量。一旦得到你所需要的信息之后，你应当立即调用removeUpdates(PendingIntent)方法停止监听
					locationManager.removeUpdates(locationListener);
					//注册监听器
					locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, locationUpdateFrequency, locationUpdateDistance, locationListener);
					locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, locationUpdateFrequency, locationUpdateDistance, locationListener);
					
				}
				if(msg.what == WHAT_DATA_UPLOAD_CHANGE_4){
					//上传服务器
					String[] uploadServer = vehiclesInfoTable.getUploadServer(vehiclesinfoId).split(Tool.SPLIT_ADDR_PORT);
					dataUploadThread.setUploadServer(new InetSocketAddress(uploadServer[0], Integer.parseInt(uploadServer[1])));
					//数据上传频率
					dataUploadFrequency = tool.getFrequency(vehiclesInfoTable.getDataUploadFrequency(vehiclesinfoId),tool.UNITS_TIME);
				}
			}
			
		}
	}
}
